package com.thermal.thermal_inspection.service.impl;

import com.thermal.thermal_inspection.service.CacheService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

@Service
public class CacheServiceImpl implements CacheService {
    private static final Logger logger = Logger.getLogger(CacheServiceImpl.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 从缓存中获取数据，若缓存中不存在，则从数据源中获取并存入缓存
     */
    @Override
    public <T, R> T getOrLoad(String key, Function<R, T> dataLoader, R input, long timeOut, TimeUnit timeUnit){

        //尝试从缓存中获取数据
        T value = (T) redisTemplate.opsForValue().get(key);

        //如果缓存中有数据，直接返回
        if(value != null){
            logger.info("从缓存中获取数据成功");
            return value;
        }
        //如果缓存中没有数据，则从数据源中获取
        value = dataLoader.apply(input);
        if(value == null){
            logger.error("未查询到结果，不存入缓存");
            return value;
        }

        //将获取到的数据存入缓存
        logger.info("缓存中未查询到数据，将数据存入缓存");
        redisTemplate.opsForValue().set(key, value, timeOut, timeUnit);

        return value;
    }

    /**
     * 无参数从缓存中获取数据，若缓存中不存在，则从数据源中获取并存入缓存
     */
    @Override
    public <T> T getOrLoad(String key, Supplier<T> dataLoader, long timeOut, TimeUnit timeUnit) {

        // 尝试从缓存中获取数据
        T value = (T) redisTemplate.opsForValue().get(key);

        // 如果缓存中有数据，直接返回
        if (value != null) {
            logger.info("从缓存中获取数据成功");
            return value;
        }

        // 如果缓存中没有数据，则从数据源中获取
        value = dataLoader.get(); // 使用 Supplier 的 get() 方法
        if (value == null) {
            logger.error("未查询到结果，不存入缓存");
            return value;
        }

        // 将获取到的数据存入缓存
        logger.info("缓存中未查询到数据，将数据存入缓存");
        redisTemplate.opsForValue().set(key, value, timeOut, timeUnit);

        return value;
    }


    /**
     * 存入键值对
     */
    @Override
    public <R> void put(String key, R value, long timeout, TimeUnit timeUnit){
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 取出键值对
     */
    @Override
    public <T> T get(String key){
        return (T)redisTemplate.opsForValue().get(key);
    }
}
